package com.haohan.cloud.scm.saleb.core.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.haohan.cloud.scm.api.constant.enums.crm.PayStatusEnum;
import com.haohan.cloud.scm.api.constant.enums.opc.YesNoEnum;
import com.haohan.cloud.scm.api.constant.enums.product.SortingStatusEnum;
import com.haohan.cloud.scm.api.constant.enums.saleb.BuyOrderStatusEnum;
import com.haohan.cloud.scm.api.constant.enums.saleb.DetailSummaryFlagEnum;
import com.haohan.cloud.scm.api.constant.enums.salec.ChannelEnum;
import com.haohan.cloud.scm.api.constant.enums.salec.UserTypeEnum;
import com.haohan.cloud.scm.api.goods.dto.GoodsModelDTO;
import com.haohan.cloud.scm.api.goods.entity.GoodsModel;
import com.haohan.cloud.scm.api.product.entity.ProductInfo;
import com.haohan.cloud.scm.api.product.entity.SortingOrderDetail;
import com.haohan.cloud.scm.api.product.feign.ProductInfoFeignService;
import com.haohan.cloud.scm.api.product.feign.SortingOrderDetailFeignService;
import com.haohan.cloud.scm.api.product.req.CreateSortingOrderReq;
import com.haohan.cloud.scm.api.product.req.QueryGoodsStorageReq;
import com.haohan.cloud.scm.api.saleb.entity.BuyOrder;
import com.haohan.cloud.scm.api.saleb.entity.BuyOrderDetail;
import com.haohan.cloud.scm.api.saleb.req.BuyOrderReq;
import com.haohan.cloud.scm.api.saleb.req.CancelBuyOrderReq;
import com.haohan.cloud.scm.api.saleb.req.CreateBuyOrderDetailReq;
import com.haohan.cloud.scm.api.saleb.req.UpdateBuyOrderStatusReq;
import com.haohan.cloud.scm.api.salec.resp.OrderMonitorResp;
import com.haohan.cloud.scm.api.wms.entity.ExitWarehouseDetail;
import com.haohan.cloud.scm.api.wms.trans.ExitWarehouseDetailTrans;
import com.haohan.cloud.scm.common.tools.exception.EmptyDataException;
import com.haohan.cloud.scm.common.tools.exception.ErrorDataException;
import com.haohan.cloud.scm.common.tools.util.RUtil;
import com.haohan.cloud.scm.saleb.core.ISalebBuyOrderService;
import com.haohan.cloud.scm.saleb.service.BuyOrderDetailService;
import com.haohan.cloud.scm.saleb.service.BuyOrderService;
import com.haohan.cloud.scm.saleb.utils.ScmSaleBUtils;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.util.R;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author dy
 * @date 2019/6/14
 */
@Service
@AllArgsConstructor
@Slf4j
public class SalebBuyOrderServiceImpl implements ISalebBuyOrderService {

    private final BuyOrderService buyOrderService;
    private final BuyOrderDetailService buyOrderDetailService;
    private final ProductInfoFeignService productInfoFeignService;
    private final SortingOrderDetailFeignService sortingOrderDetailFeignService;
    private final ScmSaleBUtils scmSaleBUtils;
    /**
     * 确认 采购单的所有明细已成交
     *
     * @param buyId
     * @return
     */
    @Override
    public Boolean confirmBuyOrder(String buyId) {
        BuyOrder buyOrder = buyOrderService.fetchBySn(buyId);
        if (null == buyOrder) {
            throw new ErrorDataException("buyId有误");
        }
        // 已成交 直接返回
        if (buyOrder.getStatus() == BuyOrderStatusEnum.success) {
            return true;
        }
        BuyOrderDetail detail = new BuyOrderDetail();
        detail.setBuyId(buyId);
        List<BuyOrderDetail> detailList = buyOrderDetailService.list(Wrappers.query(detail));
        if (CollUtil.isEmpty(detailList)) {
            throw new ErrorDataException("采购单有误");
        }
        // 判断是否所有明细已成交
        BuyOrder update = new BuyOrder();
        update.setId(buyOrder.getId());
        detail.setStatus(BuyOrderStatusEnum.success);
        int num = buyOrderDetailService.count(Wrappers.query(detail));
        boolean flag = false;
        if (num == detailList.size()) {
            update.setStatus(BuyOrderStatusEnum.success);
            flag = true;
        } else {
            update.setStatus(BuyOrderStatusEnum.wait);
        }
        buyOrderService.updateById(update);
        return flag;
    }

    /**
     * 采购明细 判断库存备货 锁定库存
     * @param buyOrderDetail
     * @return 不满足 返回false
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean detailConfirmStock(BuyOrderDetail buyOrderDetail) {
        // 判断状态 (BuyOrderStatusEnum.wait 和SummaryFlag 为0未处理) 可继续执行
        if (buyOrderDetail.getStatus() != BuyOrderStatusEnum.wait
                || buyOrderDetail.getSummaryFlag() != DetailSummaryFlagEnum.wait) {
            return false;
        }
            // 查当前商品的实际库存
            QueryGoodsStorageReq req = new QueryGoodsStorageReq();
            req.setGoodsModelId(buyOrderDetail.getGoodsModelId());
            req.setPmId(buyOrderDetail.getPmId());
            R<ProductInfo> productInfoR = productInfoFeignService.queryGoodsStorage(req, SecurityConstants.FROM_IN);
            if(!RUtil.isSuccess(productInfoR)){
                throw new EmptyDataException("库存查询有误");
            }
            ProductInfo info = BeanUtil.toBean(productInfoR.getData(), ProductInfo.class);
            // 不满足 返回false
            if(info.getProductNumber().compareTo(buyOrderDetail.getGoodsNum()) < 0){
                return false;
            }

        // 创建出库单明细(锁库存)
        BuyOrder buyOrder = buyOrderService.fetchBySn(buyOrderDetail.getBuyId());
        if(buyOrder == null){
            throw new EmptyDataException();
        }
        ExitWarehouseDetail exitWarehouseDetail = ExitWarehouseDetailTrans.createDetailByBuyOrderDetail(info, buyOrderDetail,buyOrder);
        //锁定库存
        scmSaleBUtils.createExitDetailStock(exitWarehouseDetail);

            // 满足 修改summary_flag ->2已备货   (summary_flag  0未处理  1已汇总 2已备货)
            BuyOrderDetail detail = new BuyOrderDetail();
            detail.setId(buyOrderDetail.getId());
            detail.setSummaryFlag(DetailSummaryFlagEnum.prepare);
            buyOrderDetailService.updateById(detail);
            // 对应分拣单明细修改: (状态->2可分拣) 关联货品(拆分)
            SortingOrderDetail sortingOrderDetail = new SortingOrderDetail();
            sortingOrderDetail.setPmId(buyOrderDetail.getPmId());
            sortingOrderDetail.setBuyDetailSn(buyOrderDetail.getBuyDetailSn());
            sortingOrderDetail.setSortingStatus(SortingStatusEnum.sorting);
            if(!scmSaleBUtils.modifySortingDetailBySn(sortingOrderDetail)){
                throw new ErrorDataException("分拣单更新有误");
            }

        return true;
    }
    /**
     * 批量修改订单明细
     * @param list
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updBuyOrderDetailList(List<BuyOrderDetail> list){
        for(BuyOrderDetail detail : list){
            if(detail.getDelFlag().equals(YesNoEnum.yes.getType())){
                if(!buyOrderDetailService.removeById(detail.getId())){
                    throw new ErrorDataException();
                }
            }else{
                if(!buyOrderDetailService.updateById(detail)){
                    throw new ErrorDataException();
                }
            }
        }
        return true;
    }

    /**
     * 取消订单
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean cancelBuyOrder(CancelBuyOrderReq req) {
        String buyId = req.getBuyId();
        String pmId = req.getPmId();
        // 整个订单取消 状态需为 已下单
        if(StrUtil.isNotEmpty(buyId)){
            BuyOrder buyOrder = buyOrderService.fetchBySn(buyId);
            checkOrderToCancel(buyOrder);
            BuyOrder updateBuyOrder = new BuyOrder();
            updateBuyOrder.setId(buyOrder.getId());
            updateBuyOrder.setStatus(BuyOrderStatusEnum.cancel);
            if(StrUtil.isNotEmpty(req.getRemarks())){
                updateBuyOrder.setRemarks(req.getRemarks());
            }
            buyOrderService.updateById(updateBuyOrder);
            // 取消所有明细
            BuyOrderDetail updateDetail = new BuyOrderDetail();
            updateDetail.setStatus(BuyOrderStatusEnum.cancel);
            UpdateWrapper<BuyOrderDetail> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda()
                    .eq(BuyOrderDetail::getBuyId, buyId);
            buyOrderDetailService.update(updateDetail, updateWrapper);
        }else{
             BuyOrderDetail exist = buyOrderDetailService.fetchBySn(req.getBuyDetailSn());
             if(null == exist){
                 throw new ErrorDataException("订单明细有误");
             }
             BuyOrder buyOrder = buyOrderService.fetchBySn(exist.getBuyId());
             checkOrderToCancel(buyOrder);
            // 单个订单明细取消
            BuyOrderDetail updateDetail = new BuyOrderDetail();
            updateDetail.setStatus(BuyOrderStatusEnum.cancel);
            if(StrUtil.isNotEmpty(req.getRemarks())){
                updateDetail.setRemarks(req.getRemarks());
            }
            UpdateWrapper<BuyOrderDetail> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda()
                    .eq(BuyOrderDetail::getBuyDetailSn, req.getBuyDetailSn());
            buyOrderDetailService.update(updateDetail, updateWrapper);
        }
        return true;
    }

    private void checkOrderToCancel(BuyOrder buyOrder) {
        if (null == buyOrder) {
            throw new ErrorDataException("取消订单有误");
        }
        if (buyOrder.getStatus() != BuyOrderStatusEnum.submit) {
            throw new ErrorDataException("订单当前状态不可取消");
        }
        if (buyOrder.getPayStatus() != PayStatusEnum.wait) {
            throw new ErrorDataException("订单已支付不可取消");
        }
    }

    /**
     * 采购明细 判断库存备货 锁定库存(批量)
     * @param order
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean detailConfirmStockList(BuyOrder order) {
        BuyOrderDetail queryDetail = new BuyOrderDetail();
        queryDetail.setPmId(order.getPmId());
        queryDetail.setBuyId(order.getBuyId());
        List<BuyOrderDetail> list = buyOrderDetailService.list(Wrappers.query(queryDetail));
        for(BuyOrderDetail detail : list){
            try {
                detailConfirmStock(detail);
            }catch (Exception e){
                log.debug("锁定库存失败", e.getMessage());
            }
        }
        return true;
    }

    /**
     * 修改采购单状态 为wait
     * @param pmId
     * @param minute
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer buyOrderChangeStatusWait(String pmId, int minute) {
        // 超过时间
        LocalDateTime endTime = LocalDateTime.now().minusMinutes(minute);
        QueryWrapper<BuyOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .lt(BuyOrder::getCreateDate, endTime)
                .eq(BuyOrder::getPmId, pmId)
                .eq(BuyOrder::getStatus, BuyOrderStatusEnum.submit);
        List<BuyOrder> list = buyOrderService.list(queryWrapper);
        if(CollUtil.isEmpty(list)){
            return 0;
        }
        BuyOrder update = new BuyOrder();
        UpdateWrapper<BuyOrderDetail> updateWrapper;
        BuyOrderDetail updateDetail = new BuyOrderDetail();
        updateDetail.setStatus(BuyOrderStatusEnum.wait);
        CreateSortingOrderReq sortingReq = new CreateSortingOrderReq();
        sortingReq.setPmId(pmId);
        for (BuyOrder order : list) {
            // 调用 创建分拣单
            sortingReq.setBuyId(order.getBuyId());
            scmSaleBUtils.createSortingOrder(sortingReq);

            update.setId(order.getId());
            update.setStatus(BuyOrderStatusEnum.wait);
            buyOrderService.updateById(update);
            // 修改明细
            updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda()
                    .eq(BuyOrderDetail::getStatus, BuyOrderStatusEnum.submit)
                    .eq(BuyOrderDetail::getBuyId, order.getBuyId());
            buyOrderDetailService.update(updateDetail, updateWrapper);
            // 锁库存
            detailConfirmStockList(order);
        }
        return list.size();
    }

    /**
     * 根据商品创建订单明细
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<BuyOrderDetail> createBuyOrderDetail(CreateBuyOrderDetailReq req) {
        List<BuyOrderDetail> details = new ArrayList<>();
        for(GoodsModel model:req.getList()){
            BuyOrderDetail detail = new BuyOrderDetail();
            detail.setPmId(req.getBuyOrder().getPmId());
            detail.setBuyId(req.getBuyOrder().getBuyId());
            detail.setGoodsModelId(model.getId());
            detail.setGoodsModel(model.getModelName());
            GoodsModelDTO dto = scmSaleBUtils.queryGoodsModelById(model.getId());
            detail.setGoodsName(dto.getGoodsName());
            detail.setGoodsImg(dto.getModelUrl());
            detail.setBuyPrice(model.getModelPrice());
            detail.setStatus(req.getBuyOrder().getStatus());
            detail.setBuyerId(req.getBuyOrder().getBuyerId());
            detail.setMarketPrice(model.getCostPrice());
            detail.setUnit(model.getModelUnit());
            detail.setSummaryFlag(DetailSummaryFlagEnum.wait);
            details.add(detail);
            if(!buyOrderDetailService.save(detail)){
                throw new ErrorDataException("创建订单明细失败");
            }
        }
        return details;
    }

    /**
     * 查询b订单
     * @param req
     * @return
     */
    @Override
    public List<OrderMonitorResp> queryBuyOrderByTime(BuyOrderReq req) {
        List<OrderMonitorResp> resp = buyOrderService.queryBuyOrderByTime(req);
        List<OrderMonitorResp> result = new ArrayList<>();
        for(OrderMonitorResp res :resp){
            BigDecimal decimal = buyOrderDetailService.queryPriceSum(res.getOrderId());
            res.setGoodsNum(decimal.intValue());
            if(res.getContent() != null && StrUtil.isNotEmpty(res.getContent()) && res.getContent().indexOf("|") != -1){
                String[] split = res.getContent().split("|");
                res.setLng(split[0]);
                res.setLat(split[1]);
            }else{
                res.setLat("38.6518");
                res.setLng("104.07642");
            }
            if(res.getOrderAmt() == null){
                BuyOrderReq re = new BuyOrderReq();
                re.setBuyId(res.getOrderId());
                res.setOrderAmt(buyOrderService.fetchBySn(res.getOrderId()).getGenPrice());
            }
            res.setUserType(UserTypeEnum.Saleb.getDesc());
            if(res.getChannel() == null){
                res.setChannel(ChannelEnum.pc.getDesc());
            }else{
                res.setChannel(ChannelEnum.getByType(res.getChannel()).getDesc());
            }
            res.setContent("");
            result.add(res);
        }
        return result;
    }

    /**
     * 修改B订单及明细的状态
     * @param req
     * @return  执行失败抛出异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateBuyOrderStatus(UpdateBuyOrderStatusReq req) {
        String pmId = req.getPmId();
        String buyId = req.getBuyId();
        // 修改 状态/运费
        BuyOrder update = new BuyOrder();
        update.setStatus(req.getStatus());
        update.setShipFee(req.getShipFee());
        UpdateWrapper<BuyOrder> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda()
                .eq(BuyOrder::getPmId, pmId)
                .eq(BuyOrder::getBuyId, buyId);
        if(!buyOrderService.update(update, updateWrapper)){
            throw new ErrorDataException("B订单修改失败");
        }
        UpdateWrapper<BuyOrderDetail> detailWrapper;
        BuyOrderDetail updateDetail = new BuyOrderDetail();
        for(BuyOrderDetail detail: req.getDetailList()){
            detailWrapper = new UpdateWrapper<>();
            detailWrapper.lambda()
                    .eq(BuyOrderDetail::getPmId, pmId)
                    .eq(BuyOrderDetail::getBuyId, buyId)
                    .eq(BuyOrderDetail::getBuyDetailSn, detail.getBuyDetailSn());
            updateDetail.setStatus(detail.getStatus());
            updateDetail.setGoodsNum(detail.getGoodsNum());
            if(!buyOrderDetailService.update(updateDetail, detailWrapper)){
                throw new ErrorDataException("B订单明细修改失败");
            }
        }
    }

    /**
     * 订单确认收货 交易完成  pmId / buyId
     *   执行失败抛出异常
     * @param buyOrder
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmReceive(BuyOrder buyOrder) {
        String pmId = buyOrder.getPmId();
        String buyId = buyOrder.getBuyId();
        // 查询采购单
        BuyOrder order = buyOrderService.fetchBySn(buyId);
        if (null == order || order.getStatus() !=  BuyOrderStatusEnum.arrive) {
            throw new ErrorDataException("B订单当前状态不可确认收货");
        }
        // 查询明细 不为取消
        QueryWrapper<BuyOrderDetail> queryDetail = new QueryWrapper<>();
        queryDetail.lambda()
                .eq(BuyOrderDetail::getPmId, pmId)
                .eq(BuyOrderDetail::getBuyId, buyId)
                .ne(BuyOrderDetail::getStatus, BuyOrderStatusEnum.cancel);
        List<BuyOrderDetail> list = buyOrderDetailService.list(queryDetail);
        BigDecimal total = BigDecimal.ZERO;
        for (BuyOrderDetail detail : list) {
            total = total.add(detail.getGoodsNum().multiply(detail.getBuyPrice()));
        }
        // 修改明细 不为取消
        BuyOrderDetail updateDetail = new BuyOrderDetail();
        updateDetail.setStatus(BuyOrderStatusEnum.success);
        if (!buyOrderDetailService.update(updateDetail, queryDetail)) {
            throw new ErrorDataException("B订单明细修改失败");
        }
        // 修改采购单
        BuyOrder update = new BuyOrder();
        update.setId(order.getId());
        update.setStatus(BuyOrderStatusEnum.success);
        if (null == order.getShipFee()) {
            update.setShipFee(BigDecimal.ZERO);
        } else {
            total = total.add(order.getShipFee());
        }
        update.setTotalPrice(total);
        buyOrderService.updateById(update);
    }

}
